package org.example.lock;

import lombok.extern.slf4j.Slf4j;
import org.example.bean.LockResult;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Service
@Slf4j
public class LockManage {
    private static final int MIN_WAIT_TIME = 10;

    @Resource
    private RedissonClient redissonClient;

    public LockResult lock(String key, long expireTime, long waitTime){
        //return lock(key, expireTime, waitTime, () -> new RuntimeException("加锁失败"));
        if(waitTime < MIN_WAIT_TIME){
            waitTime = MIN_WAIT_TIME;
        }
        LockResult lockResult = new LockResult();
        RLock rLock = redissonClient.getLock(key);
        try {
            if(rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS)){
                lockResult.setLockResultStatus("success");
                lockResult.setRLock(rLock);
            }else{
                lockResult.setLockResultStatus("failure");
            }
        } catch (InterruptedException e) {
            log.error("redis获取分布式锁失败，key:{}， e:{}", key, e.getMessage());
            lockResult.setLockResultStatus("exception");
            rLock.unlock();
        }

        log.info("redis加锁结果：{}，key:{}", lockResult.getLockResultStatus(), key);
        return lockResult;
    }

    public LockResult lock(String key, long expireTime, long waitTime, Supplier<RuntimeException> exceptionSupplier){
        if(waitTime < MIN_WAIT_TIME){
            waitTime = MIN_WAIT_TIME;
        }
        LockResult lockResult = new LockResult();
        RLock rLock = redissonClient.getLock(key);
        try {
            if(rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS)){
                lockResult.setLockResultStatus("success");
                lockResult.setRLock(rLock);
            }else{
                lockResult.setLockResultStatus("failure");
            }
        } catch (InterruptedException e) {
            log.error("redis获取分布式锁失败，key:{}， e:{}", key, e.getMessage());
            lockResult.setLockResultStatus("exception");
            rLock.unlock();
        }

        if(exceptionSupplier!=null && "failure".equals(lockResult.getLockResultStatus())){
            log.warn("redis加锁失败， key:{}", key);
            throw exceptionSupplier.get();
        }

        log.info("redis加锁结果：{}，key:{}", lockResult.getLockResultStatus(), key);
        return lockResult;
    }

    public void unlock(RLock rLock){
        rLock.unlock();
    }

}
